package com.jy.app.lib.net;

import android.annotation.SuppressLint;
import android.content.Context;
import android.util.Log;

import com.alibaba.fastjson.JSON;
import com.jy.app.lib.utils.JsonUtil;
import com.jy.app.lib.utils.LogUtil;
import com.loopj.android.http.AsyncHttpResponseHandler;

import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import cz.msebera.android.httpclient.Header;
import cz.msebera.android.httpclient.message.BasicHeader;
import cz.msebera.android.httpclient.util.TextUtils;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;


/**
 * Http请求工具类
 * Created by jan on 2016/3/28.
 *
 * @version 1.1
 */
public class OkHttpUtil {
    //是否打印数据日志
    public static final boolean ENABLE_LOG = true;
    public static final String CONTENT_TYPE = "application/json; charset=utf-8";
    public static boolean IS_HTTPS = false;

    private static OkHttpClient getClient(){
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(20, TimeUnit.SECONDS);//设置连接超时时间
        builder.readTimeout(20, TimeUnit.SECONDS);//设置读取超时时间
        if (IS_HTTPS){
            builder.dns(new ApiDns());
            builder.sslSocketFactory(createSSLSocketFactory());
            builder.hostnameVerifier(new TrustAllHostnameVerifier());
        }
        return builder.build();
    }

    @SuppressLint("TrulyRandom")
    private static SSLSocketFactory createSSLSocketFactory() {

        SSLSocketFactory sSLSocketFactory = null;

        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, new TrustManager[]{new TrustAllManager()},
                    new SecureRandom());
            sSLSocketFactory = sc.getSocketFactory();
        } catch (Exception e) {
        }

        return sSLSocketFactory;
    }

    @Deprecated
    public static <T> void httpGet(Context context, String url, String params, HttpResponseHandler<T> handler) {
    }

    public static <T> void httpGet(String url, AsyncHttpResponseHandler handler) {
        Request request = new Request.Builder().get().url(url).build();
        newCall(request,handler);
    }

    public static <T> void httpGet(String url, Map<String,String> params, JsonResponseHttpHandler<T> handler) {
        Request request = new Request.Builder().get().url(attachHttpGetParams(url,params)).build();
        newCall(request,handler);
    }

    public static <T> void httpPut(Context context, String url, String params, AsyncHttpResponseHandler handler) {
        RequestBody requestBody = FormBody.create(MediaType.parse(CONTENT_TYPE),params);
        Request request = new Request.Builder().url(url).put(requestBody).build();
        newCall(request,handler);
    }

    public static <T> void httpGet(String url,Map<String,String> params, HttpResponseHandler<T> handler) {
        Request request = new Request.Builder().get().url(attachHttpGetParams(url,params)).build();
        newCall(request,handler);
    }

    public static <T> void httpGet(String url, Map<String,String> params, AsyncHttpResponseHandler handler) {
        Request request = new Request.Builder().get().url(attachHttpGetParams(url,params)).build();
        newCall(request,handler);
    }

    public static void httpPost(String url, Map<String,String> params, CommonHttpResponseHandler handler) {
        Request request = new Request.Builder().post(mapToFormBody(params)).url(url).build();
        newCall(request,handler);
    }

    public static void httpPost(String url, Map<String,String> params, FileHttpResponseHandler handler) {
        Request request = new Request.Builder().post(mapToFormBody(params)).url(url).build();
        newCall(request,handler);
    }

    public static <T> void httpPost(final Context context, final String url, final String params, final HttpResponseHandler<T> handler) {
        RequestBody requestBody = FormBody.create(MediaType.parse(CONTENT_TYPE),params);
        Request request = new Request.Builder().url(url).post(requestBody).build();
        newCall(request,handler);
    }

    public static <T> void httpPost(Context context, String url, String params, CommonHttpResponseHandler handler) {
        RequestBody requestBody = FormBody.create(MediaType.parse(CONTENT_TYPE),params);
        Request request = new Request.Builder().url(url).post(requestBody).build();
        newCall(request,handler);
    }

    public static <T> void httpPost(Context context, String url, String params, ProwlJsonResponseHttpHandler handler) {
        RequestBody requestBody = FormBody.create(MediaType.parse(CONTENT_TYPE),params);
        Request request = new Request.Builder().url(url).post(requestBody).build();
        newCall(request,handler);
    }

    public static <T> void httpPost(Context context, String url, String params, JsonResponseHttpHandler<T> handler) {
        RequestBody requestBody = FormBody.create(MediaType.parse(CONTENT_TYPE),params);
        Request request = new Request.Builder().url(url).post(requestBody).build();
        newCall(request,handler);
    }

    public static void httpPost(Context context, String url, String params, AsyncHttpResponseHandler handler) {
        RequestBody requestBody = FormBody.create(MediaType.parse(CONTENT_TYPE),params);
        Request request = new Request.Builder().url(url).post(requestBody).build();
        newCall(request,handler);
    }

    public static <T> void get(String url, HttpResponseHandler<T> httpHandler) {
        httpGet(url, httpHandler);
    }

    public static void get(String url, AsyncHttpResponseHandler httpHandler) {
        httpGet(url, httpHandler);
    }

    @Deprecated
    public static <T> void get(Context context, String url, Map params, HttpResponseHandler<T> httpHandler) {
    }

    public static <T> void get(final String url, final Map params, final JsonResponseHttpHandler<T> httpHandler) {
       httpGet(url, params, httpHandler);
    }

    public static void get(final String url, final Map params, final AsyncHttpResponseHandler httpHandler) {
            httpGet(url,params, httpHandler);
    }

    public static <T> void getSimple(Context context,final String url, final Map params, final JsonHttpHandler<T> httpHandler) {
        if(context != null){
            httpHandler.setDialogMsg(context,"正在请求数据...");
        }
            httpGet(url,params, httpHandler);
    }

    public static <T> void getSimple(final String url, final Map params, final JsonHttpHandler<T> httpHandler) {
        getSimple(null,url,params,httpHandler);
    }

    public static <T> void get(final String url, final Map params, final HttpResponseHandler<T> httpHandler) {
            httpGet(url,params, httpHandler);
    }

    public static <T> void get(final String url, final Map params, final ProwlJsonResponseHttpHandler<T> handler) {
            httpGet(url, params, handler);
    }

    public static <T> void post(final Context context, final String url, final Map params, final HttpResponseHandler<T> httpHandler) {
            String request = JsonUtil.toJson(params);
            httpPost(context, url, request, httpHandler);
    }

    public static <T> void post(final Context context, final String url, final Map params, final JsonResponseHttpHandler<T> httpHandler) {
            String request = JsonUtil.toJson(params);
            httpPost(context, url, request, httpHandler);
    }

    public static <T> void postSimple(final Context context, String msg, final String url, final Map params, final JsonHttpHandler<T> jsonHttpHandler) {

        if(!TextUtils.isEmpty(msg)){
            jsonHttpHandler.setDialogMsg(context,msg);
        }
            String request = JsonUtil.toJson(params);
            httpPost(context, url, request, jsonHttpHandler);
    }

    public static <T> void postSimple(final Context context, final String url, final Map params, final JsonHttpHandler<T> jsonHttpHandler) {
        postSimple(context,null, url,params, jsonHttpHandler);
    }

    public static <T> void post(Context context, String url, Object params, JsonResponseHttpHandler<T> httpHandler) {
          String request = JsonUtil.toJson(params);
          httpPost(context, url, request, httpHandler);
    }

    public static void post(final Context context, final String url, final Map params, final CommonHttpResponseHandler httpHandler) {
            String request = JsonUtil.toJson(params);
            httpPost(context, url, request, httpHandler);
    }

    public static <T> void post(Context context, String url, List params, ProwlJsonResponseHttpHandler<T> httpHandler) {
                String request = JsonUtil.toJson(params);
                httpPost(context, url, request, httpHandler);
    }

    public static void post(final Context context, final String url, final Map params, final ProwlJsonResponseHttpHandler httpHandler) {
            String request = JsonUtil.toJson(params);
            httpPost(context, url, request, httpHandler);
    }

    public static void post(final String url, final Map params, final AsyncHttpResponseHandler httpHandler) {
        Request request = new Request.Builder().post(mapToFormBody(params)).url(url).build();
        newCall(request,httpHandler);
    }

    public static void post(String url, Map params, FileHttpResponseHandler httpHandler) {
        Request request = new Request.Builder().post(mapToFormBody(params)).url(url).build();
        newCall(request,httpHandler);
    }

    public static <T> void uploadFile(String upUrl, String filePath, Map map, CommonHttpResponseHandler httpHandler) {
        RequestBody multipartBody = new MultipartBody.Builder()
                .setType(MultipartBody.ALTERNATIVE)
                //一样的效果
                .addPart(Headers.of("Content-Disposition","form-data; name=\"params\""),mapToFormBody(map))
                .addPart(Headers.of("Content-Disposition","form-data; name=\"file\"; filename=\"plans.xml\""),
                        RequestBody.create(MediaType.parse("application/octet-stream"),new File(filePath)))
                .build();
        Request request=new Request.Builder().url(upUrl)
                .addHeader("User-Agent","android")
                .header("Content-Type","text/html; charset=utf-8;")
                .post(multipartBody)
                .build();
        newCall(request,httpHandler);
    }

    public static void uploadFiles(String upUrl, List<String> filePath, FileHttpResponseHandler httpHandler) {
        MediaType MutilPart_Form_Data = MediaType.parse("multipart/form-data; charset=utf-8");
        RequestBody bodyParams = RequestBody.create(MutilPart_Form_Data, JSON.toJSONString(new HashMap<>()));
        MultipartBody.Builder requestBodyBuilder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("keyVo", "", bodyParams);
        //循环添加文件
        for (int i = 0; i < filePath.size(); i++) {
            File file = new File(filePath.get(i));
            requestBodyBuilder.addFormDataPart("imgs", file.getName(), RequestBody.create(MutilPart_Form_Data, new File(filePath.get(i))));
        }
        RequestBody requestBody = requestBodyBuilder.build();
        Request request = new Request.Builder()
                .url( upUrl)
                .post(requestBody)
                .build();
        newCall(request,httpHandler);
    }

    /**
     * 将okHttp回调转换为asyncHttp回调
     * */
    private static void newCall(final Request request, final AsyncHttpResponseHandler responseHandler){
        final OkHttpClient client = getClient();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                // 程序出错时调用
                if (responseHandler != null) responseHandler.onFailure(10000,new Header[]{}
                ,("网络连接错误"+e.toString()).getBytes(),e);
                client.dispatcher().cancelAll();
                client.connectionPool().evictAll();
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (responseHandler != null && response != null) {
                    String str = response.body().string();
                    Log.i("HttpUtil code=", response.code() + "");
                    Log.i("HttpUtil url=", response.request().url().toString());
                    Log.i("HttpUtil request=", str);
                    if (response.isSuccessful()) {//判断返回code是否在200-300之间
                        responseHandler.onSuccess(response.code(), toHeader(response.headers()), str.getBytes());
                    } else {
                        responseHandler.onFailure(response.code(), toHeader(response.headers()), (TextUtils.isEmpty(str) ? "" : str).getBytes(),
                                new Throwable(TextUtils.isEmpty(response.message()) ? "" : response.message()));
                        client.dispatcher().cancelAll();
                    }
                }
            }
        });
    }

    private static Header[] toHeader(Headers headers){
        if (headers == null || headers.size()==0) return new BasicHeader[]{};
        BasicHeader[] headers1 = new BasicHeader[headers.size()];
        for (int i = 0 ,size = headers.size() ; i<size ;i++){
            headers1[i] = new BasicHeader(headers.name(i),headers.value(i));
        }
        return headers1;
    }


    /**
     * 为HttpGet 的 url 方便的添加多个name value 参数。
     * @param url
     * @param params
     * @return
     */
    private static String attachHttpGetParams(String url, Map<String,String> params){
        Iterator<String> keys = params.keySet().iterator();
        Iterator<String> values = params.values().iterator();
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("?");

        for (int i=0;i<params.size();i++ ) {
            String value = null;
            String key = keys.next();
            try {
                value = URLEncoder.encode(values.next(), "utf-8");
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (!TextUtils.isEmpty(value)) {
                stringBuffer.append( key+ "=" + value);
                if (i != params.size() - 1) {
                    stringBuffer.append("&");
                }
            }
        }
        return url + stringBuffer.toString();
    }

    private static FormBody mapToFormBody(Map<String,String> params){
        if (params == null) return new FormBody.Builder().build();
        FormBody.Builder formBody = new FormBody.Builder();
                for (String key :params.keySet()){
                    if (!TextUtils.isEmpty(params.get(key)))
                    formBody.add(key,params.get(key));
                }
        return formBody.build();
    }


    private static void logD(String type, String content) {
        logD(type,null,content);
    }
    private static void logD(String type,String url, String content) {
        if (ENABLE_LOG) {
            if(url!=null){
                LogUtil.d("[HttpUtil][" + type + "] [url="+ url+"] [request=" + content+"]");
            }else {
                LogUtil.d("[HttpUtil][" + type + "]request=" + content);
            }
        }
    }

    private static class TrustAllManager implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }

    private static class TrustAllHostnameVerifier implements HostnameVerifier {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }
}
